package cc.core.pullrefresh;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.LayoutRes;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.ListAdapter;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
import com.nineoldandroids.view.ViewHelper;

import cc.core.pullrefresh.extra.BaseFooterLayout;
import cc.core.pullrefresh.extra.BaseHeaderLayout;
import cc.core.pullrefresh.extra.FooterLayout;
import cc.core.pullrefresh.extra.HeaderLayout;
import cc.core.pullrefresh.extra.ILayoutBase;
import cc.core.pullrefresh.extra.OnPullListener;

/**
 * ClassName:PullRefreshBase <br/>
 * Date: 2015年6月22日 下午3:37:57 <br/>
 *
 * @author YuanChao
 */
public abstract class PullRefreshBase<T extends View> extends LinearLayout implements IPullBase<T> {

    protected OnScrollListener onScrollListener;

    /**
     * 下拉刷新的Header和上拉加载更多的View
     */
    protected BaseFooterLayout footerView;
    protected BaseHeaderLayout headerView;

    protected T refreshView;
    protected OnPullListener pullListener;
    /**
     * 封装ListView的容器
     */
    protected LinearLayout layoutBase;

    protected AttributeSet attr;

    protected OnRefreshListener refreshListener;

    protected int state, mode;

    protected float mLastMotionY;
    protected float mInitialMotionY;
    protected float mInitY, mInitFirstChildY;
    protected float mHeaderY;
    protected final float STICKY = 2.0f;
    protected float lastScrollValue;

    protected boolean once;
    protected boolean headerScrolling;
    protected boolean shouldMeasureInitY = true;// 是否应该计算initY
    protected boolean isPulling;
    protected boolean isPullDown;
    protected boolean refreshAnimStarted = false;// 拉手刷新时，会加载动画滑动到Header的高度

    protected int headerHeight;
    protected int footerHeight;
    protected int newScrollValue;
    protected int pullLimitDistance;


    public PullRefreshBase(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context, attrs);
    }

    public PullRefreshBase(Context context) {
        super(context);
        initView(context, null);
    }

    protected void initView(Context context, AttributeSet attrs) {
        layoutBase = new LinearLayout(context);
        layoutBase.setOrientation(VERTICAL);
        layoutBase.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        refreshView = initRefreshView(context, attrs, 0);
        refreshView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        if (attrs != null) {
            TypedArray ta = context.obtainStyledAttributes(attrs,
                    R.styleable.PullRefresh);
            int headRes = ta.getResourceId(R.styleable.PullRefresh_headerRes, -1);
            int footRes = ta.getResourceId(R.styleable.PullRefresh_footerRes, -1);
            pullLimitDistance = (int) ta.getDimension(R.styleable.PullRefresh_pullLimitDistance, -1);
            if (headRes > 0) {
                headerView = (BaseHeaderLayout) LayoutInflater.from(context).inflate(headRes, null);
            }
            if (footRes > 0) {
                footerView = (BaseFooterLayout) LayoutInflater.from(context).inflate(footRes, null);
            }

            ta.recycle();
        }
        this.attr = attrs;

        innerInit(context);
        setOrientation(VERTICAL);

        initHeader(context, attr);

        if (!(headerView instanceof ILayoutBase)) {
            throw new IllegalArgumentException("Have you let your Headview implements ILayoutBase?");
        }

        layoutBase.addView(headerView);
        layoutBase.addView(refreshView);

        addView(layoutBase);
        this.attr = attrs;
        setMode(Mode.PULL_FROM_TOP);
    }


    /**
     * <p>
     * 设置下拉刷新的模式，你应该在{@link #setAdapter(ListAdapter)}之前调用这个方法
     * </p>
     *
     * @param mode
     */
    public void setMode(int mode) {
        this.mode = mode;
    }

    public int getMode() {
        return mode;
    }


    /**
     * 设置{@link #headerView}
     */
    @Override
    public void initHeader(Context context, AttributeSet attr) {
        if (headerView == null)
            headerView = new HeaderLayout(getContext(), attr);
        headerHeight = measureHeight(headerView);
        if (pullLimitDistance <= 0) {
            pullLimitDistance = headerHeight;
        }
        LayoutParams lp = (LayoutParams) layoutBase.getLayoutParams();
        initHeadMargin(lp, -headerHeight);
        layoutBase.setLayoutParams(lp);

    }

    public void setHeaderView(@LayoutRes int layoutRes) {
        setHeaderView((BaseHeaderLayout) LayoutInflater.from(getContext()).inflate(layoutRes, null));
    }

    public void setHeaderView(BaseHeaderLayout view) {
        try {
            layoutBase.removeView(headerView);
        } catch (Exception e) {
            e.printStackTrace();
        }
        headerView = view;
        layoutBase.addView(headerView, 0);
        initHeader(getContext(), attr);
        shouldMeasureInitY = true;
        updateFirstChildY();
    }

    public void setFooterView(@LayoutRes int layoutRes) {
        setFooterView((BaseFooterLayout) LayoutInflater.from(getContext()).inflate(layoutRes, null));
    }

    public void setFooterView(BaseFooterLayout footerView) {
        this.footerView = footerView;
        initFooter(getContext(), attr);
    }


    protected abstract void updateFirstChildY();

    /**
     * 设置{@link #footerView}
     */
    @Override
    public void initFooter(Context context, AttributeSet attr) {
        if (footerView == null)
            footerView = new FooterLayout(getContext(), attr);
        footerHeight = measureHeight(footerView);
    }

    protected int measureHeight(View view) {
        int w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        view.measure(w, h);
        return view.getMeasuredHeight();
    }

    protected void initHeadMargin(LayoutParams lp, int height) {
        lp.setMargins(0, height, 0, 0);
    }

    protected void innerInit(Context context) {
        refreshView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {

                if (!shouldMeasureInitY)
                    return;
                mInitY = getLc(layoutBase.getChildAt(1))[1];
                shouldMeasureInitY = !shouldMeasureInitY;
            }
        });
        // 不显示顶部和底部拖拽时的阴影
        // if (Integer.parseInt(Build.VERSION.SDK) >= 9) {
        // this.setOverScrollMode(View.OVER_SCROLL_NEVER);
        // }
    }

    /**
     * <h1>下拉的具体实现。</h1>
     * <p>
     * 通过计算计算手指滑动的距离，不断地改变{@link #layoutBase}的Y以达到下移效果
     * </p>
     */
    @Override
    public void doMove(MotionEvent ev) {
        final float initialMotionValue, lastMotionValue;

        initialMotionValue = mInitialMotionY;
        lastMotionValue = mLastMotionY;

        setPressed(false);
        newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / STICKY);

        if (readyPull(ev)) {
            updateHead();
            ViewHelper.setTranslationY(layoutBase, -newScrollValue);
            headerView.setAnimValue(-newScrollValue);
            if (pullListener != null && -newScrollValue >= 0) {
                pullListener.onPullDown(-newScrollValue);
            }
        }
    }

    /**
     * <p>
     * 初始化 listview分别调用它的不同参数的构造方法，以使xml里可以使用listview 的属性
     * </p>
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    protected abstract T initRefreshView(Context context, AttributeSet attrs, int defStyleAttr);

    protected void updateHead() {

    }

    @Override
    public void setOnRefreshListener(OnRefreshListener listener) {
    }

    public void setOnPullListener(OnPullListener pullListener) {
        this.pullListener = pullListener;
    }

    protected boolean childTouchEvnet(MotionEvent ev) {

        if (mode == Mode.DISABLE)
            return false;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = mInitialMotionY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                mLastMotionY = ev.getY();
                doMove(ev);
                break;
        }
        if (isPulling || headerScrolling)
            return true;
        else
            return false;
    }

    @Override
    public T getRefreshView() {
        return null;
    }

    public int getHeaderHeight() {
        return headerHeight;
    }

    public int getPullLimitDistance() {
        return pullLimitDistance;
    }

    /**
     * Attention!
     *
     * @param pullLimitDistanceDP Attention! The unit is DP!
     */
    public void setPullLimitDistance(int pullLimitDistanceDP) {
        pullLimitDistance = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                pullLimitDistanceDP, getResources().getDisplayMetrics());
    }

    @Override
    public void setEmptyView(View view) {
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
    }

    public void startHeadAnim(float... value) {
        float startValue, endValue;
        ObjectAnimator anim = null;
        if (value.length == 1) {
            startValue = value[0];
            anim = ObjectAnimator.ofFloat(layoutBase, "translationY", startValue).setDuration(300);
        } else {
            startValue = value[0];
            endValue = value[1];
            anim = ObjectAnimator.ofFloat(layoutBase, "translationY", startValue, endValue).setDuration(300);
        }
//		CoreUtil.DEBUG_D("mInitY:" + mInitY + ",Y:" + ",headerHeight:" + headerHeight);
        anim.addListener(new Animator.AnimatorListener() {
            boolean isRefreshAnim = false;// 是否需要执行下拉刷新时加载的动画

            public void onAnimationStart(Animator animator) {
                if (refreshAnimStarted)
                    isRefreshAnim = true;
                refreshAnimStarted = false;
                headerScrolling = true;
                state = State.HEAD_RELEASEING;
            }

            public void onAnimationEnd(Animator animator) {
                if (isRefreshAnim) {
                    isRefreshAnim = false;
                    headerScrolling = true;
                    state = State.HEAD_REFRESHING;
//					updateState();
                } else {
                    state = State.NORMAL;
                }
                headerScrolling = false;
//				updateState();
                shouldMeasureInitY = true;
                innerInit(getContext());
            }

            public void onAnimationCancel(Animator animator) {
            }

            public void onAnimationRepeat(Animator animator) {
            }
        });
        anim.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // ViewHelper.setRotation(headerImg,
                // (Float) animation.getAnimatedValue());
                Float value = (Float) animation.getAnimatedValue();
                if (pullListener != null && value >= 0)
                    pullListener.onPullDown(value);
                ((ILayoutBase) headerView).setAnimValue(value);
                updateHead();
            }
        });
        anim.start();
    }

    @Override
    public boolean readyPull(MotionEvent ev) {
        return false;
    }

    public int[] getLc(View view) {
        int[] lc = new int[]{0, 0};
        if (view != null) {
            view.getLocationInWindow(lc);
        }
        return lc;
    }

    @Override
    public void showHeaderRefresh() {
    }

    public OnScrollListener getOnScrollListener() {
        return onScrollListener;
    }

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public static class Mode {
        public static final int DISABLE = -1;
        public static final int PULL_FROM_TOP = 0;
        public static final int PULL_FROM_BOTTOM = 2;
        public static final int BOTH = 3;
    }

    public static class State {

        /**
         * no refreshing,normal status.
         */
        public static final int NORMAL = 0;

        /**
         * pulling down from top,and the pulling distance have not reach the refreshing status.
         */
        public static final int HEAD_PULLING = 1;

        /**
         * now refreshing.
         */
        public static final int HEAD_REFRESHING = 2;

        /**
         * release to refresh(pull distance had reached the refreshing status.)
         */
        public static final int HEAD_RELEASEING = 3;

        @Deprecated
        public static final int FOOTER_PULLING = 4;


        /**
         * footerview is showing and loading more.
         */
        public static final int FOOTER_REFRESHING = 5;


        @Deprecated
        public static final int FOOTER_RELEASEING = 6;
    }

    public int getState() {
        return state;
    }

    public LinearLayout getContainer() {
        return layoutBase;
    }

}
